package fileHandling;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import settings.CheatConfig;
import settings.Config;
import settings.ConfigFile;
import settings.ControlSettings;
import settings.CommonSettings;
import settings.FilterSettings;
import settings.GraphicSettings;
import settings.SoundSettings;

/**
 * Provides static methods to load, check and create files of profiles.
 * 
 * @author Wasserleiche
 */
public class ProfileHandler {
	
	private final static String PROFILE_PATH = "data/profiles/";
	private final static String SELECTED_PROFILE_FILE = "selectedProfile.txt";
	private final static String DEFAULT_PROFILE_PATH = "data/defaultSettings/";
	
	private final static ConfigFile[] CONFIG_FILES = new ConfigFile[] {
		ControlSettings.get(), CommonSettings.get(), GraphicSettings.get(), FilterSettings.get(), Config.get(), 
		CheatConfig.get(), SoundSettings.get()
	};
	
	public static void initSettings() {
		initSettings(getSelectedProfile());
	}
	
	public static void initSettings(String profile) {
		String settingsPath = PROFILE_PATH + profile + "/";
		if(profile == null) settingsPath = DEFAULT_PROFILE_PATH;
		
		for(ConfigFile cg : CONFIG_FILES) {
			cg.readSettings(settingsPath + cg.getFileName());
		}
	}
	
	public static void changeSettings(ConfigFile settings) {
		changeSettings(settings, getSelectedProfile());
	}
	
	public static void changeSettings(ConfigFile settings, String name) {
		String file = settings.getFileName();
		SettingsLoader.saveSettings(PROFILE_PATH + name + "/" + file, settings);
	}
	
	/**
	 * Creates a new profile with the given profile-name and initializes it. If it is not possible to create 
	 * all files an error-message will be displayed.
	 * @param name The name of the profile that is to be created.
	 */
	public static void createNewProfileFiles(String name) {
		try {
			File path = new File(PROFILE_PATH + name);
			if(!path.mkdir()) return;
			
			String pathName = PROFILE_PATH + name + "/";
			for(ConfigFile cg : CONFIG_FILES) {
				String configPath = pathName + cg.getFileName();
				File configFile = new File(configPath);
				configFile.createNewFile();
				cg.readSettings(DEFAULT_PROFILE_PATH + cg.getFileName());
				changeSettings(cg, name);
			}
			
			initSettings(name);
		} catch(IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Returns all available profiles.
	 * @return A {@link List} of all available profiles.
	 */
	public static List<String> getProfiles() {
		List<String> profiles = new LinkedList<String>();
		File f = new File(PROFILE_PATH);
		File[] fileArray = f.listFiles();
		for(int i = 0; i < fileArray.length; i++) {
			if(fileArray[i].isDirectory() && !fileArray[i].getPath().contains(".")) {
				profiles.add(fileArray[i].getName());
			}
		}
		return profiles;
	}
	
	/**
	 * Checks all available profiles using checkFiles(). If a profile does not stand the check, it will be 
	 * recreated using createNewProfileFiles(). If the selected profile is not available, the default profile will 
	 * be used.
	 */
	public static void checkProfiles() {
		List<String> profiles = getProfiles();
		
		for(String profileName : profiles) {
			if(!checkFiles(profileName)) 
				createNewProfileFiles(profileName);
		}
	}
	
	/**
	 * Checks if the file that contains the selected profile can be read. If not, a new file will be created. If that is 
	 * not possible, an error-message will be created. Otherwise the default profile will be used.
	 */
	public static void checkSelectedProfile() {
		String selectedPath = PROFILE_PATH + SELECTED_PROFILE_FILE;
		
		File selectedFile = new File(selectedPath);
		
		if(!selectedFile.exists()) {
			try { selectedFile.createNewFile(); }
			catch(Exception e1) { e1.printStackTrace(); }
		}
	}
	
	/**
	 * Checks if all files of the given profile can be read.
	 * @param profileName The name of the profile to be checked.
	 * @return true, if no errors occurred while reading the files of the profile. false, otherwise.
	 */
	private static boolean checkFiles(String profileName) {
		try {
			testFile(PROFILE_PATH + profileName + "/" + ControlSettings.get().getFileName());
			testFile(PROFILE_PATH + profileName + "/" + CommonSettings.get().getFileName());
			testFile(PROFILE_PATH + profileName + "/" + GraphicSettings.get().getFileName());
			testFile(PROFILE_PATH + profileName + "/" + FilterSettings.get().getFileName());
			testFile(PROFILE_PATH + profileName + "/" + Config.get().getFileName());
			testFile(PROFILE_PATH + profileName + "/" + CheatConfig.get().getFileName());
			return true;
		} catch(Exception e) { return false; }
	}
	
	private static void testFile(String path) throws Exception {
		BufferedReader reader = null;
		try { reader = new BufferedReader(new FileReader(path)); }
		finally {
			if(reader != null) reader.close();
		}
	}
	
	/**
	 * Reads the file where the selected profile is stored and returns its content.
	 * @return The selected profile if the selected profile file can be read. The default profile, otherwise.
	 */
	public static String getSelectedProfile() {
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(PROFILE_PATH + SELECTED_PROFILE_FILE));
			String selectedProfile = reader.readLine();
			return selectedProfile;
		} catch(Exception e) { 
			e.printStackTrace();
		} finally {
			if(reader != null) {
				try { reader.close(); }
				catch(Exception e) { e.printStackTrace(); }
			}
		}
		return null;
	}
	
	public static boolean isAutoLogin() {
		if(getSelectedProfile() == null) return false;
		
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(PROFILE_PATH + SELECTED_PROFILE_FILE));
			reader.readLine();
			return Boolean.valueOf(reader.readLine()).booleanValue();
		} catch(Exception e) { 
			e.printStackTrace();
		} finally {
			if(reader != null) {
				try { reader.close(); }
				catch(Exception e) { e.printStackTrace(); }
			}
		}
		return false;
	}
	
	/**
	 * The given profile becomes the selected profile. If that's not possible, an error-message will be displayed.
	 * @param newDefaultProfile The profile name to become the selected profile.
	 */
	public static void setSelectedProfile(String newDefaultProfile, boolean autoLogin) {
		BufferedWriter writer = null;
		try {
			File selectedProfileFile = new File(PROFILE_PATH + SELECTED_PROFILE_FILE);
			selectedProfileFile.createNewFile();
			writer = new BufferedWriter(new FileWriter(PROFILE_PATH + SELECTED_PROFILE_FILE));
			writer.write(newDefaultProfile);
			writer.write("\n" + autoLogin);
			initSettings(newDefaultProfile);
		} catch(IOException e) {
			e.printStackTrace();
		} finally {
			if(writer != null) {
				try { writer.close(); }
				catch(Exception e) { e.printStackTrace(); }
			}
		}
	}
}